package org.sdnstproject.interlayer.OF13Protocal;

import java.util.Arrays;
import java.util.HashMap;
import java.util.Random;

import org.projectfloodlight.openflow.exceptions.OFParseError;
import org.projectfloodlight.openflow.protocol.OFFactories;
import org.projectfloodlight.openflow.protocol.OFMessage;
import org.projectfloodlight.openflow.protocol.OFPacketIn;
import org.projectfloodlight.openflow.protocol.OFVersion;
import org.projectfloodlight.openflow.protocol.match.Match;
import org.projectfloodlight.openflow.types.U16;
import org.projectfloodlight.openflow.types.U32;
import org.sdnstproject.interlayer.interlayerProxy.DummyOF13;
import org.sdnstproject.interlayer.utils.Utils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;

public class FuPacketIn {
	private static final Logger log = LoggerFactory.getLogger(FuPacketIn.class);
    public byte version = (byte)4;
    public byte type = (byte)10;
    public short length = (short)8;//变长
    public long xid = 0x0L;//需要dummyswitch设置
    /*private final int rawValue;
    private OFBufferId(int rawValue) {
        this.rawValue = rawValue;
    }*/
    public int bufferId = 260;
    public int totalLen = 90;
    /*public static void writeTo(ByteBuf bb, OFPacketInReason e) {
        bb.writeByte(toWireValue(e));
    }*/
    /*reason:
     *   NO_MATCH_VAL = (byte) 0x0;
      ACTION_VAL = (byte) 0x1;
      INVALID_TTL_VAL = (byte) 0x2;
      BSN_NEW_HOST_VAL = (byte) 0x80;
      BSN_STATION_MOVE_VAL = (byte) 0x81;
      BSN_BAD_VLAN_VAL = (byte) 0x82;
      BSN_DESTINATION_LOOKUP_FAILURE_VAL = (byte) 0x83;
      BSN_NO_ROUTE_VAL = (byte) 0x84;
      BSN_ICMP_ECHO_REQUEST_VAL = (byte) 0x85;
      BSN_DEST_NETWORK_UNREACHABLE_VAL = (byte) 0x86;
      BSN_DEST_HOST_UNREACHABLE_VAL = (byte) 0x87;
      BSN_DEST_PORT_UNREACHABLE_VAL = (byte) 0x88;
      BSN_FRAGMENTATION_REQUIRED_VAL = (byte) 0x89;
      BSN_ARP_VAL = (byte) 0x8b;
      BSN_DHCP_VAL = (byte) 0x8c;
      BSN_DEBUG_VAL = (byte) 0x8d;
      BSN_PACKET_OF_DEATH_VAL = (byte) 0x8e;
     * */
    public byte reason = 0x0;
    public byte tableId = 0x0;
    public long cookie = 0x0;
    public byte[] match = Utils.hexStringToByteArray("0001000c800000040000000100000000");
    public byte[] data = Utils.hexStringToByteArray("3333000000160ae8bf550be586dd600000000024000100000000000000000000000000000000ff0200000000000000000000000000163a000502000001008f0063500000000104000000ff0200000000000000000001ff550be5");
    
    public FuPacketIn() {
    	
    }
    
    public FuPacketIn setField(String field, String value) {
		switch (field) {
		case "version":
			this.version = Byte.parseByte(value);
			break;
		case "type":
			this.type = Byte.parseByte(value);
			break;
		case "length":
			this.length = Short.parseShort(value);
			break;
		case "xid":
			this.xid = Long.parseLong(value);
			break;
		case "bufferId":
			this.bufferId = Integer.parseInt(value);
			break;
		case "totalLen":
			this.totalLen = Integer.parseInt(value);
			break;
		case "reason":
			this.reason = Byte.parseByte(value);
			break;
		case "tableId":
			this.tableId = Byte.parseByte(value);
			break;
		case "cookie":
			this.cookie = Long.parseLong(value);
			break;
		case "match":
			this.match = new byte[16];//The length of match is fixed at 16.
			new Random().nextBytes(match);
			break;
		case "data":
			this.data = new byte[new Random().nextInt(40)+44];
			new Random().nextBytes(data);
			break;
		}
		return this;
	}
    
    public HashMap<String, String> FuPacketInFields = new HashMap<String, String>() {
		{
			put("version","byte");
			put("type","byte");
			put("length","short");
			put("xid","long");
			put("bufferId", "int");
			put("totalLen", "int");
			put("reason", "byte");
			put("tableId", "byte");
			put("cookie", "long");
			put("match", "byte[]");
			put("data", "byte[]");
		}
    };
    
	public ByteBuf writeTo() {
		ByteBuf bb = Unpooled.directBuffer();
        int startIndex = bb.writerIndex();
        // fixed value property version = 4
        bb.writeByte(version);
        // fixed value property type = 10
        bb.writeByte(type);
        // length is length of variable message, will be updated at the end
        int lengthIndex = bb.writerIndex();
        bb.writeShort(U16.t(0));

        bb.writeInt(U32.t(xid));
        bb.writeInt(bufferId);
        bb.writeShort(U16.t(totalLen));
        bb.writeByte(reason);
        bb.writeByte(tableId);
        bb.writeLong(cookie);
        bb.writeBytes(match);
        // pad: 2 bytes
        bb.writeZero(2);
        bb.writeBytes(data);

        // update length field
        length = (short)(bb.writerIndex() - startIndex);
        bb.setShort(lengthIndex, length);
        return bb;
    }
	@Override
    public String toString() {
        StringBuilder b = new StringBuilder("FuPacketInVer13(");
        b.append("version=").append(version);
        b.append(", ");
        b.append("type=").append(type);
        b.append(", ");
        b.append("length=").append(length);
        b.append(", ");
        b.append("xid=").append(xid);
        b.append(", ");
        b.append("bufferId=").append(bufferId);
        b.append(", ");
        b.append("totalLen=").append(totalLen);
        b.append(", ");
        b.append("reason=").append(reason);
        b.append(", ");
        b.append("tableId=").append(tableId);
        b.append(", ");
        b.append("cookie=").append(cookie);
        b.append(", ");
        b.append("match=").append(Arrays.toString(match));
        b.append(", ");
        b.append("data=").append(Arrays.toString(data));
        b.append(")");
        return b.toString();
    }
}
